home *** CD-ROM | disk | FTP | other *** search
/ IRIX 6.5 Complementary Applications 2004 February / SGI IRIX 6.5 Complementary Applications 2004 February.iso / dist / cde.idb / usr / dt / share / examples / motif / draganddrop / DNDDemo.c.z / DNDDemo.c
Encoding:
C/C++ Source or Header  |  2003-11-18  |  51.9 KB  |  1,778 lines

  1. /*
  2.  * DNDDemo.c
  3.  *
  4.  * Copyright 2000, Silicon Graphics, Inc.
  5.  * ALL RIGHTS RESERVED
  6.  * 
  7.  * UNPUBLISHED -- Rights reserved under the copyright laws of the United
  8.  * States.   Use of a copyright notice is precautionary only and does not
  9.  * imply publication or disclosure.
  10.  *
  11.  * U.S. GOVERNMENT RESTRICTED RIGHTS LEGEND:
  12.  * Use, duplication or disclosure by the Government is subject to restrictions
  13.  * as set forth in FAR 52.227.19(c)(2) or subparagraph (c)(1)(ii) of the Rights
  14.  * in Technical Data and Computer Software clause at DFARS 252.227-7013 and/or
  15.  * in similar or successor clauses in the FAR, or the DOD or NASA FAR
  16.  * Supplement.  Contractor/manufacturer is Silicon Graphics, Inc.,
  17.  * 2011 N. Shoreline Blvd. Mountain View, CA 94039-7311.
  18.  *
  19.  * THE CONTENT OF THIS WORK CONTAINS CONFIDENTIAL AND PROPRIETARY
  20.  * INFORMATION OF SILICON GRAPHICS, INC. ANY DUPLICATION, MODIFICATION,
  21.  * DISTRIBUTION, OR DISCLOSURE IN ANY FORM, IN WHOLE, OR IN PART, IS STRICTLY
  22.  * PROHIBITED WITHOUT THE PRIOR EXPRESS WRITTEN PERMISSION OF SILICON
  23.  * GRAPHICS, INC.
  24.  */
  25. /* 
  26.  * (c) Copyright 1989, 1990, 1991, 1992 OPEN SOFTWARE FOUNDATION, INC. 
  27.  * ALL RIGHTS RESERVED 
  28. */ 
  29. /* 
  30.  * Motif Release 1.2
  31. */ 
  32. #ifdef REV_INFO
  33. #ifndef lint
  34. static char rcsid[] = "$XConsortium: DNDDemo.c /main/cde1_maint/1 1995/07/14 13:58:42 drk $"
  35. #endif
  36. #endif
  37. /*
  38. *  (c) Copyright 1987, 1988, 1989 HEWLETT-PACKARD COMPANY */
  39. /*
  40.  *    file: DNDDemo.c
  41.  *
  42.  *    A demo program showing the basic Drag And Drop operations.
  43.  */
  44.  
  45. #include "DNDDemo.h"
  46.  
  47.  
  48. /*
  49.  * The folowing character arrays are for use with the drop help
  50.  * dialogs.  For internationalization, message catalogs should
  51.  * replace these static declarations.
  52.  */
  53. char HELP_MSG1[] = 
  54. "This drop action will change the color\n\
  55. of the rectangle that the paint palette\n\
  56. icon is dropped on. To accept this drop\n\
  57. press the o.k. button, otherwise press\n\
  58. cancel";
  59.  
  60. char HELP_MSG2[] = 
  61. "This drop action will move the rectangle\n\
  62. to the new position.  To accept this drop\n\
  63. press the o.k. button, otherwise press\n\
  64. cancel";
  65.  
  66. char HELP_MSG3[] = 
  67. "This drop action will copy the rectangle\n\
  68. to the new position.  To accept this drop\n\
  69. press the o.k. button, otherwise press\n\
  70. cancel";
  71.  
  72. char HELP_MSG4[] = 
  73. "This drop action can either copy or\n\
  74. move the rectangle to the new position.\n\
  75. Select the operation that you desire.\n\
  76. In the future, use Ctrl with Btn2 to\n\
  77. perform copy operations.  The default\n\
  78. operation is move.  To accept this drop\n\
  79. press the o.k. button, otherwise press\n\
  80. cancel";
  81.  
  82. char HELP_MSG5[] = 
  83. "This drop action is at an Invalid drop\n\
  84. position.  Please cancel this drop \n\
  85. by pressing the cancel button.";
  86.  
  87.  
  88. /* Globals variables */
  89. Widget          topLevel;
  90. Widget          drawingArea;
  91. Widget          helpDialog = NULL;
  92. Widget          helpLabel, helpMenu;
  93. Widget          myDC;
  94. XtAppContext    appContext;
  95.  
  96.  
  97. /* This function creates the Drag Icon. */
  98. static Widget
  99. #ifdef _NO_PROTO
  100. GetDragIcon(w, icon, iconMask, width, height, background, foreground)
  101. Widget w;
  102. Pixmap icon;
  103. Pixmap iconMask;
  104. Dimension width;
  105. Dimension height;
  106. Pixel background;
  107. Pixel foreground;
  108. #else
  109. GetDragIcon(Widget w, Pixmap icon, Pixmap iconMask, Dimension width,
  110. Dimension height, Pixel background, Pixel foreground)
  111. #endif /* _NO_PROTO */
  112. {
  113.  
  114.     Widget  dragIcon;
  115.     Arg     args[10];
  116.     int     n = 0;
  117.  
  118.     XtSetArg(args[n], XmNhotX, ICON_X_HOT); n++;
  119.     XtSetArg(args[n], XmNhotY, ICON_Y_HOT); n++;
  120.     XtSetArg(args[n], XmNwidth, width); n++;
  121.     XtSetArg(args[n], XmNheight, height); n++;
  122.     XtSetArg(args[n], XmNmaxWidth, appInfo->maxCursorWidth); n++;
  123.     XtSetArg(args[n], XmNmaxHeight, appInfo->maxCursorHeight); n++;
  124.     XtSetArg(args[n], XmNbackground, background); n++;
  125.     XtSetArg(args[n], XmNforeground, foreground); n++;
  126.     XtSetArg(args[n], XmNpixmap, icon); n++;
  127.     XtSetArg(args[n], XmNmask, iconMask); n++;
  128.     dragIcon = XmCreateDragIcon(w, "dragIcon", args, n);
  129.  
  130.     return(dragIcon);
  131.  
  132. }
  133.  
  134.  
  135. /* This function creates the bitmaps for the icon and the mask
  136.  * and then calls GetDragIcon() to  create the drag icon.
  137.  */
  138. static Widget
  139. #ifdef _NO_PROTO
  140. GetDragIconFromBits(w, bits, mask, width, height, background, foreground)
  141. Widget w;
  142. char *bits;
  143. char *mask;
  144. Dimension width;
  145. Dimension height;
  146. Pixel background;
  147. Pixel foreground;
  148. #else
  149. GetDragIconFromBits(Widget w, char *bits, char *mask, Dimension width,
  150.                     Dimension height, Pixel background, Pixel foreground)
  151. #endif /* _NO_PROTO */
  152. {
  153.  
  154.     Pixmap     icon, iconMask;
  155.     Display    *display = XtDisplay(w);
  156.  
  157.     icon = XCreateBitmapFromData(display, DefaultRootWindow(display), bits, 
  158.                                  width, height);
  159.  
  160.     iconMask = XCreateBitmapFromData(display, DefaultRootWindow(display),
  161.                                      mask, width, height);
  162.  
  163.     return(GetDragIcon(w, icon, iconMask, width, height, 
  164.                        background, foreground));
  165.  
  166. }
  167.  
  168.  
  169. /* This function creates the rectangle bitmaps for the icon and
  170.  * the mask based on the maximum server allowable cursor size
  171.  * and then calls GetDragIcon() to create the drag icon.
  172.  */
  173. static Widget
  174. #ifdef _NO_PROTO
  175. GetDragIconFromRect(w, rect, background)
  176. Widget w;
  177. RectPtr rect;
  178. Pixel background;
  179. #else
  180. GetDragIconFromRect(Widget w, RectPtr rect, Pixel background)
  181. #endif /* _NO_PROTO */
  182. {
  183.  
  184.     Pixmap      icon, icon_mask;
  185.     Pixel       foreground = RectGetColor(rect);
  186.     Dimension   width, height;
  187.  
  188.     /* Create a depth 1 pixmap (bitmap) for use with the drag icon */
  189.     icon = icon_mask = GetBitmapFromRect(w, rect, background, foreground, 
  190.                                          &width, &height);
  191.  
  192.     /* use bitmap for both the bitmap and mask */
  193.     return(GetDragIcon(w, icon, icon_mask, width, height, 
  194.                        background, foreground));
  195.  
  196. }
  197.  
  198.  
  199. /* This is a selection conversion function that is used in
  200.  * converting drag/drop export background color targets.
  201.  * The return types follow ICCC statndards.
  202.  */
  203. /* ARGSUSED */
  204. Boolean
  205. #ifdef _NO_PROTO
  206. ColorConvert(w, selection, target, type, value, length, format)
  207. Widget w ;
  208. Atom *selection ;
  209. Atom *target ;
  210. Atom *type ;
  211. XtPointer *value ;
  212. unsigned long *length ;
  213. int *format ;
  214. #else
  215. ColorConvert(Widget w, Atom *selection, Atom *target, Atom *type,
  216. XtPointer *value, unsigned long *length, int *format)
  217. #endif /* _NO_PROTO */
  218. {
  219.  
  220.     Display     *display = XtDisplay(w);
  221.     Atom        BACKGROUND = XmInternAtom(display, "BACKGROUND", False);
  222.     Atom        PIXEL = XmInternAtom(display, "PIXEL", False);
  223.     Atom        TARGETS = XmInternAtom(display, "TARGETS", False);
  224.     Atom        MULTIPLE = XmInternAtom(display, "MULTIPLE", False);
  225.     Atom        TIMESTAMP = XmInternAtom(display, "TIMESTAMP", False);
  226.     int         MAX_TARGS = 5;
  227.     Widget      widget;
  228.     XtPointer   client;
  229.     Arg         args[1];
  230.  
  231.     /* get the widget that initiated the drag */
  232.     XtSetArg(args[0], XmNclientData, &client);
  233.     XtGetValues(w, args, 1);
  234.     widget = (Widget) client;
  235.  
  236.     /* Make sure we are doing a motif drag by checking if the widget that
  237.    * is passed in is a drag context. Make sure the widget in the client
  238.    * data is not NULL.
  239.    */
  240.     if (!XmIsDragContext(w) || widget == NULL)
  241.         return False;
  242.  
  243.     if (*target == BACKGROUND) {
  244.  
  245.         /* Get widget's background */
  246.         Pixel *background;
  247.  
  248.         background = (Pixel *) XtMalloc(sizeof(Pixel));
  249.         XtSetArg(args[0], XmNbackground, background);
  250.         XtGetValues(widget, args, 1);
  251.  
  252.         /* value, type, length, and format must be set */
  253.         *value = (XtPointer) background;
  254.         *type = PIXEL;
  255.         *length = sizeof(Pixel);
  256.         *format = 32;
  257.  
  258.     }
  259.     else if (*target == TARGETS) {
  260.  
  261.         /* This target is required by ICCC */
  262.         Atom *targs = (Atom *)XtMalloc((unsigned) (MAX_TARGS * sizeof(Atom)));
  263.         int target_count = 0;
  264.  
  265.         *value = (XtPointer) targs;
  266.         *targs++ = BACKGROUND; 
  267.         target_count++;
  268.         *targs++ = TARGETS; 
  269.         target_count++;
  270.         *targs++ = MULTIPLE; 
  271.         target_count++;  /* supported in the Intrinsics */
  272.         *targs++ = TIMESTAMP; 
  273.         target_count++; /* supported in the Intrinsics */
  274.         *type = XA_ATOM;
  275.         *length = (target_count * sizeof(Atom)) >> 2;
  276.         *format = 32;
  277.  
  278.     }
  279.     else
  280.         return False;
  281.  
  282.     return True;
  283.  
  284. }
  285.  
  286.  
  287. /* This callback procedure resets the drag icon cursor to show
  288.  * when the drag is in a valid region .  It cause the
  289.  * state icon to become visible when a drop is at a valid
  290.  * position for drag over effects.
  291.  */
  292. static void
  293. #ifdef _NO_PROTO
  294. DragMotionCallback(w, client, call)
  295. Widget w;
  296. XtPointer client;
  297. XtPointer call;
  298. #else
  299. DragMotionCallback(Widget w, XtPointer client, XtPointer call)
  300. #endif /* _NO_PROTO */
  301. {
  302.  
  303.     XmDragMotionCallback    cb = (XmDragMotionCallback) call;
  304.     Arg                     args[2];
  305.     Widget                  stateIcon, invalidIcon;
  306.  
  307.     if (cb->dropSiteStatus == XmVALID_DROP_SITE) {
  308.  
  309.         stateIcon = (Widget) client;
  310.  
  311.         XtSetArg(args[0], XmNblendModel, XmBLEND_STATE_SOURCE);
  312.         XtSetArg(args[1], XmNstateCursorIcon, stateIcon);
  313.         XtSetValues(w, args, 2);
  314.  
  315.     }
  316.     else if (cb->dropSiteStatus == XmINVALID_DROP_SITE) {
  317.  
  318.         XtSetArg(args[0], XmNdefaultInvalidCursorIcon, &invalidIcon);
  319.         XtGetValues(XmGetXmScreen(XtScreen(w)), args, 1);
  320.         XtSetArg(args[0], XmNblendModel, XmBLEND_STATE_SOURCE);
  321.         XtSetArg(args[1], XmNstateCursorIcon, invalidIcon);
  322.         XtSetValues(w, args, 2);
  323.  
  324.     }
  325.     else {
  326.         XtSetArg(args[0], XmNblendModel, XmBLEND_JUST_SOURCE);
  327.         XtSetValues(w, args, 1);
  328.     }
  329.  
  330. }
  331.  
  332.  
  333. /* This callback procedure resets the drag icon cursor to show
  334.  * when the drag is in a valid region .  It cause the
  335.  * state icon to become visible when a drop is at a valid
  336.  * position for drag over effects.
  337.  */
  338. /* ARGSUSED */
  339. static void
  340. #ifdef _NO_PROTO
  341. DropSiteLeaveCallback(w, client, call)
  342. Widget w;
  343. XtPointer client;
  344. XtPointer call;
  345. #else
  346. DropSiteLeaveCallback(Widget w, XtPointer client, XtPointer call)
  347. #endif /* _NO_PROTO */
  348. {
  349.  
  350.     Arg    args[1];
  351.  
  352.     XtSetArg(args[0], XmNblendModel, XmBLEND_JUST_SOURCE);
  353.     XtSetValues(w, args, 1);
  354.  
  355. }
  356.  
  357.  
  358. /* This callback procedure removes the icons when the drop is complete */
  359. /* ARGSUSED */
  360. static void
  361. #ifdef _NO_PROTO
  362. ColorDragDropFinishCB(w, client, call)
  363. Widget w;
  364. XtPointer client;
  365. XtPointer call;
  366. #else
  367. ColorDragDropFinishCB(Widget w, XtPointer client, XtPointer call)
  368. #endif /* _NO_PROTO */
  369. {
  370.  
  371.     Widget  sourceIcon;
  372.     Widget  stateIcon = (Widget) client;
  373.     Arg     args[1];
  374.  
  375.     XtSetArg(args[0], XmNsourceCursorIcon, &sourceIcon);
  376.     XtGetValues(w, args, 1);
  377.  
  378.     XtDestroyWidget(sourceIcon);
  379.     XtDestroyWidget(stateIcon);
  380.  
  381. }
  382.  
  383.  
  384. /* This action procedure sets up the drag data and begins the drag operation */
  385. /* ARGSUSED */
  386. void
  387. #ifdef _NO_PROTO
  388. ColorRect(w, event, params, num_params)
  389. Widget w;
  390. XEvent *event;
  391. String *params;
  392. Cardinal *num_params;
  393. #else
  394. ColorRect(Widget w, XEvent *event, String *params, Cardinal *num_params)
  395. #endif /* _NO_PROTO */
  396. {
  397.  
  398.     static XtCallbackRec dragDropFinishCB[] = { 
  399.         {ColorDragDropFinishCB, NULL},
  400.         {NULL, NULL} 
  401.     };
  402.  
  403.     static XtCallbackRec dragMotionCB[] = { 
  404.         {DragMotionCallback, NULL},
  405.         {NULL, NULL} 
  406.     };
  407.  
  408.     static XtCallbackRec dropSiteLeaveCB[] = { 
  409.         {DropSiteLeaveCallback, NULL},
  410.         {NULL, NULL} 
  411.     };
  412.  
  413.     Atom        targets[1];
  414.     Widget      sourceIcon, stateIcon;
  415.     Pixel       background, foreground;
  416.     char        *source_bits, *source_mask;
  417.     char        *state_bits, *state_mask;
  418.     Dimension   width, height;
  419.     Arg         args[16];
  420.     int         n = 0;
  421.  
  422.     n = 0;
  423.     XtSetArg(args[n], XmNbackground, &background); n++;
  424.     XtSetArg(args[n], XmNforeground, &foreground); n++;
  425.     XtGetValues(w, args, n);
  426.  
  427.     /* If the server will handle a large icon, create one */
  428.     if (appInfo->maxCursorWidth >= ICON_WIDTH &&
  429.         appInfo->maxCursorHeight >= ICON_HEIGHT) {
  430.  
  431.         source_bits = (char*)SOURCE_ICON_BITS;
  432.         source_mask = (char*)SOURCE_ICON_MASK;
  433.         state_bits = (char*)STATE_ICON_BITS;
  434.         state_mask = (char*)STATE_ICON_MASK;
  435.         width = ICON_WIDTH;
  436.         height = ICON_HEIGHT;
  437.  
  438.     }
  439.     else {
  440.  
  441.         /* If the server will handle a small icon, create one */
  442.         source_bits = (char*)SMALL_SOURCE_ICON_BITS;
  443.         source_mask = (char*)SMALL_SOURCE_ICON_MASK;
  444.         state_bits = (char*)SMALL_STATE_ICON_BITS;
  445.         state_mask = (char*)SMALL_STATE_ICON_MASK;
  446.         width = SMALL_ICON_WIDTH;
  447.         height = SMALL_ICON_HEIGHT;
  448.  
  449.     }
  450.  
  451.     /* Create the drag cursor icons */
  452.     sourceIcon = GetDragIconFromBits(w, source_bits, source_mask, width, 
  453.                                      height, background, foreground);
  454.  
  455.     stateIcon = GetDragIconFromBits(w, state_bits, state_mask, width, 
  456.                                     height, background, foreground);
  457.  
  458.     /* Setup the arglist for the drag context that is created at drag start */
  459.     n = 0;
  460.     /* initially only show the source icon */
  461.     XtSetArg(args[n], XmNblendModel, XmBLEND_JUST_SOURCE); n++;
  462.  
  463.     /* set cursor colors for the drag states */
  464.     XtSetArg(args[n], XmNvalidCursorForeground, 
  465.              GetColor(VALID_CURSOR_FG_COLOR)); n++;
  466.     XtSetArg(args[n], XmNinvalidCursorForeground,
  467.              GetColor(INVALID_CURSOR_FG_COLOR)); n++;
  468.     XtSetArg(args[n], XmNnoneCursorForeground,
  469.              GetColor(NONE_CURSOR_FG_COLOR)); n++;
  470.  
  471.     /* set args for the drag cursor icons */
  472.     XtSetArg(args[n], XmNcursorBackground, background); n++;
  473.     XtSetArg(args[n], XmNcursorForeground, foreground); n++;
  474.     XtSetArg(args[n], XmNsourceCursorIcon, sourceIcon); n++;
  475.     XtSetArg(args[n], XmNstateCursorIcon, stateIcon); n++;
  476.  
  477.     /*
  478.      * set up the available export targets.  These are targets that we
  479.      * wish to provide data on
  480.      */
  481.     targets[0] = XmInternAtom(XtDisplay(w), "BACKGROUND", False);
  482.     XtSetArg(args[n], XmNexportTargets, targets); n++;
  483.     XtSetArg(args[n], XmNnumExportTargets, 1); n++;
  484.  
  485.     /*
  486.      * identify the conversion procedure and
  487.      * the client data passed to the procedure
  488.      */
  489.     XtSetArg(args[n], XmNclientData, w); n++;
  490.     XtSetArg(args[n], XmNconvertProc, ColorConvert); n++;
  491.  
  492.     /* identify the necessary callbacks */
  493.     dragDropFinishCB[0].closure = (XtPointer) stateIcon;
  494.     XtSetArg(args[n], XmNdragDropFinishCallback, dragDropFinishCB); n++;
  495.     dragMotionCB[0].closure = (XtPointer) stateIcon;
  496.     XtSetArg(args[n], XmNdragMotionCallback, dragMotionCB); n++;
  497.     XtSetArg(args[n], XmNdropSiteLeaveCallback, dragMotionCB); n++;
  498.  
  499.     /* set the drag operations that are supported */
  500.     XtSetArg(args[n], XmNdragOperations, XmDROP_COPY); n++;
  501.  
  502.     /* start the drag.  This creates a drag context. */
  503.     myDC = XmDragStart(w, event, args, n);
  504.  
  505. }
  506.  
  507.  
  508. /*
  509.  * This is a selection conversion function that is used in
  510.  * converting requests for rectangle targets.  The return types follow
  511.  * ICCC statndards.
  512.  */
  513. /* ARGSUSED */
  514. Boolean
  515. #ifdef _NO_PROTO
  516. RectConvert( w, selection, target, type, value, length, format)
  517. Widget w ;
  518. Atom *selection ;
  519. Atom *target ;
  520. Atom *type ;
  521. XtPointer *value ;
  522. unsigned long *length ;
  523. int *format ;
  524. #else
  525. RectConvert(Widget w, Atom *selection, Atom *target, Atom *type,
  526. XtPointer *value, unsigned long *length, int *format)
  527. #endif /* _NO_PROTO */
  528. {
  529.  
  530.     Display         *display = XtDisplay(w);
  531.     Atom            MY_RECT = XmInternAtom(display, "_MY_RECTANGLE", False);
  532.     Atom            RECT_INFO = XmInternAtom(display, "RECT_INFO", False);
  533.     Atom            DELETE = XmInternAtom(display, "DELETE", False);
  534.     Atom            TARGETS = XmInternAtom(display, "TARGETS", False);
  535.     Atom            MULTIPLE = XmInternAtom(display, "MULTIPLE", False);
  536.     Atom            TIMESTAMP = XmInternAtom(display, "TIMESTAMP", False);
  537.     Atom            *targs;
  538.     int             MAX_TARGS = 6;
  539.     int             target_count;
  540.     DragConvertPtr  conv;
  541.     Widget          widget;
  542.     Arg             args[1];
  543.     RectPtr         rect, oldRect;
  544.  
  545.     /* get the widget that initiated the drag */
  546.     XtSetArg(args[0], XmNclientData, &conv);
  547.     XtGetValues(w, args, 1);
  548.     widget = (Widget) conv->widget;
  549.  
  550.     /* Make sure we are doing a motif drag by checking if the widget that
  551.    * is passed in is a drag context. Make sure the widget in the client
  552.    * data is not NULL.
  553.    */
  554.     if (!XmIsDragContext(w) || widget == NULL)
  555.         return False;
  556.  
  557.     if (*target == MY_RECT) {
  558.  
  559.         /* Create a new rectangle using information from the old retangle */
  560.         oldRect = conv->rect;
  561.  
  562.         /* We create create a new rectangle and wait for a delete target on the
  563.       * old rectangle instead of just moving the old rectangle because
  564.       * the rectangle movement might be an interclient move.
  565.       */
  566.         rect = RectCreate(oldRect->x, oldRect->y, oldRect->width,
  567.             oldRect->height, oldRect->color, oldRect->pixmap);
  568.         /* value, type, length, and format must be assigned values */
  569.         *value = (XtPointer) rect;
  570.         *type = RECT_INFO;
  571.         *length = sizeof(Pixel);
  572.         *format = 32;
  573.  
  574.     }
  575.     else if (*target == DELETE) {
  576.  
  577.         /* delete the old rectangle */
  578.         RectHide(XtDisplay(widget), XtWindow(widget), conv->rect);
  579.         RectFree(conv->rect);
  580.  
  581.         conv->rect = NULL;
  582.         /*
  583.          * DELETE target return parameters MUST be assigned as follows to
  584.          * ICCC compliant.
  585.          */
  586.         *value = NULL;
  587.         *type = XmInternAtom(XtDisplay(w), "NULL", False);
  588.         *length = 0;
  589.         *format = 8;
  590.  
  591.     }
  592.     else if (*target == TARGETS) {
  593.  
  594.         /* This target is required by ICCC */
  595.         targs = (Atom *)XtMalloc((unsigned) (MAX_TARGS * sizeof(Atom)));
  596.         target_count = 0;
  597.  
  598.         *value = (XtPointer) targs;
  599.         *targs++ = MY_RECT; 
  600.         target_count++;
  601.         *targs++ = DELETE; 
  602.         target_count++;
  603.         *targs++ = TARGETS; 
  604.         target_count++;
  605.         *targs++ = MULTIPLE; 
  606.         target_count++;  /* supported in the Intrinsics */
  607.         *targs++ = TIMESTAMP; 
  608.         target_count++; /* supported in the Intrinsics */
  609.         *type = XA_ATOM;
  610.         *length = (target_count * sizeof(Atom)) >> 2;
  611.         *format = 32;
  612.  
  613.     }
  614.     else
  615.         return False;
  616.  
  617.     return True;
  618.  
  619. }
  620.  
  621.  
  622. /* This callback procedure removes the old cursor icon */
  623. /* ARGSUSED */
  624. static void
  625. #ifdef _NO_PROTO
  626. RectDragDropFinishCB(w, client, call)
  627. Widget w;
  628. XtPointer client;
  629. XtPointer call;
  630. #else
  631. RectDragDropFinishCB(Widget w, XtPointer client, XtPointer call)
  632. #endif /* _NO_PROTO */
  633. {
  634.  
  635.     DragConvertPtr  conv = (DragConvertPtr) client;
  636.     Widget          sourceCursorIcon;
  637.     Arg             args[1];
  638.  
  639.     XtSetArg(args[0], XmNsourceCursorIcon, &sourceCursorIcon);
  640.     XtGetValues(w, args, 1);
  641.  
  642.     XtFree((char *) conv);
  643.  
  644.     XtDestroyWidget(sourceCursorIcon);
  645.  
  646. }
  647.  
  648.  
  649. /* This callback procedure redraws the rectangles once the drop is completed */
  650. /* ARGSUSED */
  651. static void
  652. #ifdef _NO_PROTO
  653. RectDropFinishCB(w, client, call)
  654. Widget w;
  655. XtPointer client;
  656. XtPointer call;
  657. #else
  658. RectDropFinishCB(Widget w, XtPointer client, XtPointer call)
  659. #endif /* _NO_PROTO */
  660. {
  661.  
  662.     DragConvertPtr    conv = (DragConvertPtr) client;
  663.  
  664.     appInfo->clearRect = NULL;
  665.     appInfo->doMove = True;
  666.     RedrawRectangles(conv->widget);
  667.  
  668. }
  669.  
  670.  
  671. /* This callback procedure handle the drawing of the target
  672.  * rectangle depending of the dropSiteStatus for drag over
  673.  * effects.
  674.  */
  675. /* ARGSUSED */
  676. static void
  677. #ifdef _NO_PROTO
  678. RectDragMotionCB(w, client, call)
  679. Widget w;
  680. XtPointer client;
  681. XtPointer call;
  682. #else
  683. RectDragMotionCB(Widget w, XtPointer client, XtPointer call)
  684. #endif /* _NO_PROTO */
  685. {
  686.  
  687.     XmDragMotionCallback    cb = (XmDragMotionCallback) call;
  688.     DragConvertPtr          conv = (DragConvertPtr) client;
  689.     Display                 *display;
  690.     Window                  window;
  691.     RectPtr                 rect;
  692.  
  693.     if (cb->dropSiteStatus == XmVALID_DROP_SITE) {
  694.  
  695.         /* re-stipple the rectangle when the poitner is inside the drop site */
  696.         if ( appInfo->clearRect == NULL && appInfo->doMove) {
  697.  
  698.             display = XtDisplay(conv->widget);
  699.             window = XtWindow(conv->widget);
  700.             rect = conv->rect;
  701.  
  702.             RectHide(display, window, rect);
  703.             RectDrawStippled(display, window, rect);
  704.  
  705.         }
  706.  
  707.     }
  708.     else {
  709.  
  710.         /* re-fill the rectangle when the poitner is outside the drop site */
  711.         if (appInfo->clearRect != NULL && appInfo->doMove) {
  712.             appInfo->clearRect = NULL;
  713.             RedrawRectangles(conv->widget);
  714.         }
  715.  
  716.     }
  717.  
  718. }
  719.  
  720.  
  721. /* This callback procedure handle the drawing of the target
  722.  * rectangle When the operation changes.
  723.  */
  724. /* ARGSUSED */
  725. static void
  726. #ifdef _NO_PROTO
  727. RectOperationChangedCB(w, client, call)
  728. Widget w;
  729. XtPointer client;
  730. XtPointer call;
  731. #else
  732. RectOperationChangedCB(Widget w, XtPointer client, XtPointer call)
  733. #endif /* _NO_PROTO */
  734. {
  735.  
  736.     XmDragMotionCallback    cb = (XmDragMotionCallback) call;
  737.     DragConvertPtr          conv = (DragConvertPtr) client;
  738.     Display                 *display;
  739.     Window                  window;
  740.     RectPtr                 rect;
  741.  
  742.     /* re-stipple the rectangle when the poitner is inside the drop site */
  743.     if ( appInfo->clearRect == NULL && appInfo->doMove) {
  744.  
  745.         display = XtDisplay(conv->widget);
  746.         window = XtWindow(conv->widget);
  747.         rect = conv->rect;
  748.  
  749.         RectHide(display, window, rect);
  750.         RectDrawStippled(display, window, rect);
  751.  
  752.     }
  753.  
  754.     /* re-fill the rectangle when the operation changes to copy */
  755.     if (appInfo->clearRect != NULL && !appInfo->doMove) {
  756.         appInfo->clearRect = NULL;
  757.         RedrawRectangles(conv->widget);
  758.     }
  759.  
  760. }
  761.  
  762.  
  763. /* This action procedure sets up the drag data and begins the drag operation */
  764. /* ARGSUSED */
  765. static void
  766. #ifdef _NO_PROTO
  767. StartMove(w, event, params, num_params)
  768. Widget w;
  769. XEvent *event;
  770. String *params;
  771. Cardinal *num_params;
  772. #else
  773. StartMove(Widget w, XEvent *event, String *params, Cardinal *num_params)
  774. #endif /* _NO_PROTO */
  775. {
  776.  
  777.     RectPtr     rect;
  778.     Position    x = event->xbutton.x;
  779.     Position    y = event->xbutton.y;
  780.     static XtCallbackRec dragDropFinishCB[] = { 
  781.         {RectDragDropFinishCB, NULL},
  782.         {NULL, NULL} 
  783.     };
  784.  
  785.     static XtCallbackRec dropFinishCB[] = { 
  786.         {RectDropFinishCB, NULL},
  787.         {NULL, NULL} 
  788.     };
  789.  
  790.     static XtCallbackRec dragMotionCB[] = { 
  791.         {RectDragMotionCB, NULL},
  792.         {NULL, NULL} 
  793.     };
  794.  
  795.     static XtCallbackRec operationChangedCB[] = { 
  796.         {RectOperationChangedCB, NULL},
  797.         {NULL, NULL} 
  798.     };
  799.  
  800.     Atom            targets[1];
  801.     Display         *display = XtDisplay(w);
  802.     Widget          sourceCursorIcon;
  803.     DragConvertPtr  conv;
  804.     Pixel           background, foreground;
  805.     Arg             args[16];
  806.     int             n = 0;
  807.  
  808.     /* find a rectangle at the given x,y position */
  809.     rect = RectFind(x, y);
  810.  
  811.     /* start move only if it begins on a rectangle */
  812.     if (rect) {
  813.  
  814.         XtSetArg(args[0], XmNbackground, &background);
  815.         XtGetValues(w, args, 1);
  816.  
  817.         foreground = RectGetColor(rect);
  818.         sourceCursorIcon = GetDragIconFromRect(w, rect, background);
  819.  
  820.         /*
  821.          * Set up information to pass to the convert
  822.          * function and callback procs.
  823.          */
  824.         conv = (DragConvertPtr) XtMalloc(sizeof(DragConvertRec));
  825.         conv->widget = w;
  826.         conv->rect = rect;
  827.  
  828.         /* On a move operation, draw the current
  829.        * rectangle as a stippled outline.
  830.        */
  831.         if (!(event->xbutton.state & ControlMask)) {
  832.             RectHide(display, XtWindow(w), rect);
  833.             RectDrawStippled(display, XtWindow(w), rect);
  834.         }
  835.         else
  836.             appInfo->doMove = False;
  837.  
  838.         /* Setup arglist for the drag context that is created at drag start */
  839.         n = 0;
  840.         /* initially only show the source icon */
  841.         XtSetArg(args[n], XmNblendModel, XmBLEND_JUST_SOURCE); n++;
  842.  
  843.         /* set args for the drag cursor icons */
  844.         XtSetArg(args[n], XmNcursorBackground, background); n++;
  845.         XtSetArg(args[n], XmNcursorForeground, foreground); n++;
  846.         XtSetArg(args[n], XmNsourceCursorIcon, sourceCursorIcon); n++;
  847.  
  848.         /*
  849.          * set up the available export targets.  These are targets that we
  850.          * wish to provide data on
  851.          */
  852.         targets[0] = XmInternAtom(display, "_MY_RECTANGLE", False);
  853.         XtSetArg(args[n], XmNexportTargets, targets); n++;
  854.         XtSetArg(args[n], XmNnumExportTargets, 1); n++;
  855.  
  856.         /*
  857.          * identify the conversion procedure and
  858.          * the client data passed to the procedure 
  859.          */
  860.         XtSetArg(args[n], XmNclientData, conv); n++;
  861.         XtSetArg(args[n], XmNconvertProc, RectConvert); n++;
  862.  
  863.         /* identify the necessary callbacks and the client data to be passed */
  864.         dragDropFinishCB[0].closure = (XtPointer) conv;
  865.         XtSetArg(args[n], XmNdragDropFinishCallback, dragDropFinishCB); n++;
  866.         dropFinishCB[0].closure = (XtPointer) conv;
  867.         XtSetArg(args[n], XmNdropFinishCallback, dropFinishCB); n++;
  868.         dragMotionCB[0].closure = (XtPointer) conv;
  869.         XtSetArg(args[n], XmNdragMotionCallback, dragMotionCB); n++;
  870.         operationChangedCB[0].closure = (XtPointer) conv;
  871.         XtSetArg(args[n], XmNoperationChangedCallback, operationChangedCB); n++;
  872.  
  873.         /* set the drag operations that are supported */
  874.         XtSetArg(args[n], XmNdragOperations, XmDROP_COPY | XmDROP_MOVE); n++;
  875.  
  876.         /* start the drag. This creates a drag context. */
  877.         myDC = XmDragStart(w, event, args, n);
  878.  
  879.     }
  880.  
  881. }
  882.  
  883.  
  884. /* This procedure searches through the export targets and
  885.  * returns flags to indicate which targets were found
  886.  */
  887. /* ARGSUSED */
  888. static void
  889. #ifdef _NO_PROTO
  890. CheckTargets(w, display, rectFound, bgFound, pixFound)
  891. Widget w;
  892. Display *display;
  893. Boolean *rectFound;
  894. Boolean *bgFound;
  895. Boolean *pixFound;
  896. #else
  897. CheckTargets(Widget w, Display *display, Boolean *rectFound,
  898. Boolean *bgFound, Boolean *pixFound)
  899. #endif /* _NO_PROTO */
  900. {
  901.  
  902.     Atom        MY_RECT = XmInternAtom(display, "_MY_RECTANGLE", False);
  903.     Atom        BACKGROUND = XmInternAtom(display, "BACKGROUND", False);
  904.     Atom        PIXMAP = XmInternAtom(display, "PIXMAP", False);
  905.     Atom        *exportTargets;
  906.     Cardinal    numExportTargets;
  907.     Arg         args[2];
  908.     int         n;
  909.  
  910.     /* Get list of transfer targets */
  911.     n = 0;
  912.     XtSetArg(args[0], XmNexportTargets, &exportTargets);
  913.     XtSetArg(args[1], XmNnumExportTargets, &numExportTargets);
  914.     XtGetValues(w, args, 2);
  915.  
  916.     /* initialize targets found flags */
  917.     *rectFound = *bgFound = *pixFound = False;
  918.  
  919.     /* search through the export targets */
  920.     for (n = 0; n < numExportTargets; n++) {
  921.  
  922.         if (exportTargets[n] == MY_RECT)
  923.             *rectFound = True;
  924.         else if (exportTargets[n] == BACKGROUND)
  925.             *bgFound = True;
  926.         else if (exportTargets[n] == PIXMAP)
  927.             *pixFound = True;
  928.  
  929.     }
  930.  
  931. }
  932.  
  933.  
  934. /* This procedure handles drop site messages and performs the
  935.  * appropriate drag under effects.
  936.  */
  937. /* ARGSUSED */
  938. static void
  939. #ifdef _NO_PROTO
  940. DragProcCallback(w, client, call)
  941. Widget w;
  942. XtPointer client;
  943. XtPointer call;
  944. #else
  945. DragProcCallback(Widget w, XtPointer client, XtPointer call)
  946. #endif /* _NO_PROTO */
  947. {
  948.  
  949.     XmDragProcCallbackStruct    *cb = (XmDragProcCallbackStruct *) call;
  950.     Display                     *display = XtDisplay(w);
  951.     Boolean                     rectFound, bgFound, pixFound;
  952.     static unsigned char        initial_operations;
  953.     static unsigned char        initial_operation;
  954.     RectPtr                     rect;
  955.  
  956.     CheckTargets(cb->dragContext, display, &rectFound, &bgFound, &pixFound);
  957.  
  958.     switch(cb->reason) {
  959.  
  960.         case XmCR_DROP_SITE_ENTER_MESSAGE:
  961.  
  962.             /* save the value of the operations and operation fields */
  963.             initial_operations = cb->operations;
  964.             initial_operation = cb->operation;
  965.  
  966.             rect = RectFind(cb->x, cb->y);
  967.  
  968.             /* Remove any operations for the operations field which do not 
  969.              * apply to the simulated drop site.
  970.              */
  971.             if (rect) {
  972.  
  973.                 if (bgFound || pixFound) {
  974.                     cb->operations = XmDROP_COPY;
  975.                     RectHighlight(w, rect);
  976.                 }
  977.                 else if (rectFound) {
  978.                     cb->operations = cb->operations & 
  979.                                      (XmDROP_COPY | XmDROP_MOVE);
  980.                     RectUnhighlight(w);
  981.                 }
  982.  
  983.             }
  984.             else {
  985.                 cb->operations = initial_operations & 
  986.                                  (XmDROP_COPY | XmDROP_MOVE);
  987.                 RectUnhighlight(w);
  988.             }
  989.  
  990.             /* Set operation to the valid operation preferred by the simulated 
  991.              * drop site or to XmDROP_NOOP if the operations list does not
  992.              * contain the preferred operation.
  993.              */
  994.             if (rect) {
  995.  
  996.                 if (bgFound || pixFound) {
  997.  
  998.                     if (cb->operations & XmDROP_COPY)
  999.                         cb->operation = XmDROP_COPY;
  1000.                     else
  1001.                         cb->operation = XmDROP_NOOP;
  1002.  
  1003.                 }
  1004.                 else if (rectFound) {
  1005.  
  1006.                     if (cb->operations & XmDROP_MOVE)
  1007.                         cb->operation = XmDROP_MOVE;
  1008.                     else if (cb->operations & XmDROP_COPY)
  1009.                         cb->operation = XmDROP_COPY;
  1010.                     else
  1011.                         cb->operation = XmDROP_NOOP;
  1012.  
  1013.                 }
  1014.  
  1015.             }
  1016.             else {
  1017.  
  1018.                 if (rectFound) {
  1019.  
  1020.                     if (cb->operations & XmDROP_MOVE)
  1021.                         cb->operation = XmDROP_MOVE;
  1022.                     else if (cb->operations & XmDROP_COPY)
  1023.                         cb->operation = XmDROP_COPY;
  1024.                     else
  1025.                         cb->operation = XmDROP_NOOP;
  1026.  
  1027.                 }
  1028.                 else
  1029.                     cb->operation = initial_operation;
  1030.  
  1031.             }
  1032.  
  1033.             /*
  1034.              * Set dropSiteStatus to XmDROP_SITE_INVALID if the operation 
  1035.              * field is XmDROP_NOOP, or if there are no common targets 
  1036.              * between the source and the nested drop site.  Otherwise, set 
  1037.              * dropSiteStatus to XmDROP_SITE_VALID. 
  1038.              */
  1039.             if (cb->operation == XmDROP_NOOP ||
  1040.                 (rect && (!rectFound && !bgFound && !pixFound)) ||
  1041.                 (!rect && !rectFound))
  1042.                 cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1043.             else
  1044.                 cb->dropSiteStatus = XmVALID_DROP_SITE;
  1045.     
  1046.             /*
  1047.              * Display appropriate drag under visuals.  Only highlight
  1048.              * the rectangle if we are changing rectangle attributes.
  1049.              */
  1050.             if (rect && bgFound || pixFound &&
  1051.                 cb->dropSiteStatus == XmVALID_DROP_SITE)
  1052.                 RectHighlight(w, rect);
  1053.             break;
  1054.  
  1055.         case XmCR_DROP_SITE_LEAVE_MESSAGE:
  1056.  
  1057.             /* Only unhighlight the rectangle if previously highlighted */
  1058.             if (appInfo->highlightRect != NULL)
  1059.                 RectUnhighlight(w);
  1060.             break;
  1061.  
  1062.         case XmCR_DROP_SITE_MOTION_MESSAGE:
  1063.  
  1064.             rect = RectFind(cb->x, cb->y);
  1065.  
  1066.             /*
  1067.              * Remove any operations for the operations field which do not 
  1068.              * apply to the simulated drop site.
  1069.              */
  1070.             if (rect) {
  1071.  
  1072.                 if (bgFound || pixFound) {
  1073.                     cb->operations = XmDROP_COPY;
  1074.                     RectHighlight(w, rect);
  1075.                 }
  1076.                 else if (rectFound) {
  1077.                     cb->operations = cb->operations & 
  1078.                                      (XmDROP_COPY | XmDROP_MOVE);
  1079.                     RectUnhighlight(w);
  1080.                 }
  1081.  
  1082.             }
  1083.             else {
  1084.                 cb->operations = initial_operations & 
  1085.                                  (XmDROP_COPY | XmDROP_MOVE);
  1086.                 RectUnhighlight(w);
  1087.             }
  1088.  
  1089.             /*
  1090.              * Set operation to the valid operation preferred by the simulated 
  1091.              * drop site or to XmDROP_NOOP if the operations list does not
  1092.              * contain the preferred operation.
  1093.              */
  1094.             if (rect) {
  1095.  
  1096.                 if (bgFound || pixFound) {
  1097.  
  1098.                     if (cb->operations & XmDROP_COPY)
  1099.                         cb->operation = XmDROP_COPY;
  1100.                     else
  1101.                         cb->operation = XmDROP_NOOP;
  1102.  
  1103.                 }
  1104.                 else if (rectFound) {
  1105.  
  1106.                     if (cb->operations & XmDROP_MOVE)
  1107.                         cb->operation = XmDROP_MOVE;
  1108.                     else if (cb->operations & XmDROP_COPY)
  1109.                         cb->operation = XmDROP_COPY;
  1110.                     else
  1111.                         cb->operation = XmDROP_NOOP;
  1112.  
  1113.                 }
  1114.             }
  1115.             else {
  1116.  
  1117.                 if (rectFound) {
  1118.                     if (cb->operations & XmDROP_MOVE)
  1119.                         cb->operation = XmDROP_MOVE;
  1120.                     else if (cb->operations & XmDROP_COPY) 
  1121.                         cb->operation = XmDROP_COPY;
  1122.                     else 
  1123.                         cb->operation = XmDROP_NOOP;
  1124.  
  1125.                 }
  1126.                 else
  1127.                     cb->operation = initial_operation;
  1128.  
  1129.             }
  1130.     
  1131.             /*
  1132.              * Set dropSiteStatus to XmDROP_SITE_INVALID if the operation 
  1133.              * field is XmDROP_NOOP, or if there are no common targets 
  1134.              * between the source and the nested drop site.  Otherwise, 
  1135.              * set dropSiteStatus to XmDROP_SITE_VALID.
  1136.              */
  1137.             if (cb->operation == XmDROP_NOOP ||
  1138.                 (rect && (!rectFound && !bgFound && !pixFound)) ||
  1139.                 (!rect && !rectFound))
  1140.                 cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1141.             else
  1142.                 cb->dropSiteStatus = XmVALID_DROP_SITE;
  1143.     
  1144.             /*
  1145.              * Display appropriate drag under visuals.  Only highlight
  1146.              * the rectangle if we are changing rectangle attributes.
  1147.              */
  1148.             if (rect && bgFound || pixFound &&
  1149.                 cb->dropSiteStatus == XmVALID_DROP_SITE)
  1150.                 RectHighlight(w, rect);
  1151.             break;
  1152.  
  1153.         case XmCR_OPERATION_CHANGED:
  1154.  
  1155.             if (rectFound) {
  1156.  
  1157.                 if (cb->operation == XmDROP_MOVE)
  1158.                     appInfo->doMove = True;
  1159.                 else
  1160.                     appInfo->doMove = False;
  1161.  
  1162.             }
  1163.             break;
  1164.  
  1165.         default:
  1166.  
  1167.             /* other messages we consider invalid */
  1168.             cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1169.             break;
  1170.  
  1171.     }
  1172.  
  1173.     /* allow animation to be performed */
  1174.     cb->animate = True;
  1175.  
  1176. }
  1177.  
  1178.  
  1179. /* This procedure handles the data that is being transfer */
  1180. /* ARGSUSED */
  1181. static void
  1182. #ifdef _NO_PROTO
  1183. TransferProcCallback(w, closure, seltype, type, value, length, format)
  1184. Widget w;
  1185. XtPointer closure ;
  1186. Atom *seltype ;
  1187. Atom *type ;
  1188. XtPointer value ;
  1189. unsigned long *length ;
  1190. int *format ;
  1191. #else
  1192. TransferProcCallback(Widget w, XtPointer closure, Atom *seltype, Atom *type,
  1193. XtPointer value, unsigned long *length, int *format)
  1194. #endif /* _NO_PROTO */
  1195. {
  1196.  
  1197.     DropTransfer    transferRec = (DropTransfer) closure;
  1198.     Widget          wid = transferRec->widget;
  1199.     Display         *display = XtDisplay(wid);
  1200.     Atom            RECT_INFO = XmInternAtom(display, "RECT_INFO", False);
  1201.     Atom            PIXEL = XmInternAtom(display, "PIXEL", False);
  1202.     Atom            NULL_ATOM = XmInternAtom(display, "NULL", False);
  1203.     Arg             args[10];
  1204.     RectPtr         rect;
  1205.     int             n;
  1206.  
  1207.     /*
  1208.      * The delete target returns a NULL_ATOM type and value equal to NULL 
  1209.      * so it isn't a failure.  Otherwise, check for NULL value or targets 
  1210.      * that wee don't support and set transfer failure.
  1211.      */
  1212.     if (*type != NULL_ATOM && (!value ||
  1213.         (*type != RECT_INFO && *type != PIXEL && *type != XA_DRAWABLE))) {
  1214.  
  1215.         n = 0;
  1216.         /*
  1217.          * On failures set both transferStatus to XmTRANSFER_FAILURE and
  1218.          * numDropTransfers to 0.
  1219.          */
  1220.         XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
  1221.         XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
  1222.         XtSetValues(w, args, n);
  1223.         /* Free the value if there is one, or we would have a memory leak */
  1224.         if (value)
  1225.             XtFree(value);
  1226.  
  1227.         return;
  1228.  
  1229.     }
  1230.  
  1231.     /* Handle pixel type (i.e. change in background) */
  1232.     if (*type == PIXEL) {
  1233.         rect = RectFind(transferRec->x, transferRec->y);
  1234.         RectSetColor(rect, display, XtWindow(wid), *((Pixel*)value));
  1235.     }
  1236.     /* Handle drawable type (i.e. change in pixmap) */
  1237.     else if (*type == XA_DRAWABLE) {
  1238.         rect = RectFind(transferRec->x, transferRec->y);
  1239.         RectSetPixmap(rect, display, XtWindow(wid), *((Pixmap *)value));
  1240.     }
  1241.     /* Handle rect_info type (i.e. new rectangle) */
  1242.     else if (*type == RECT_INFO) {
  1243.         rect = (RectPtr) value;
  1244.         RectRegister(rect, transferRec->x, transferRec->y);
  1245.         value = NULL; /* No need to free, it is being stored in RecTable */
  1246.     }
  1247.  
  1248.     /* Free the value if there is one, or we would have a memory leak */
  1249.     if (value)
  1250.         XtFree(value);
  1251.  
  1252. }
  1253.  
  1254.  
  1255. /* This procedure frees the data used the data transfer proc that
  1256.  * was passed from the drop procedure.
  1257.  */
  1258. /* ARGSUSED */
  1259. static void
  1260. #ifdef _NO_PROTO
  1261. DropDestroyCB(w, clientData, callData)
  1262. Widget      w;
  1263. XtPointer   clientData;
  1264. XtPointer   callData;
  1265. #else
  1266. DropDestroyCB(Widget w, XtPointer clientData, XtPointer callData)
  1267. #endif /* NO_PROTO */
  1268. {
  1269.     XtFree((char *)clientData);
  1270. }
  1271.  
  1272.  
  1273. /* This procedure initiates the drop transfer. */
  1274. /* ARGSUSED */
  1275. static void
  1276. #ifdef _NO_PROTO
  1277. HandleDrop(w, call)
  1278. Widget w;
  1279. XtPointer call;
  1280. #else
  1281. HandleDrop(Widget w, XtPointer call)
  1282. #endif /* _NO_PROTO */
  1283. {
  1284.     static XtCallbackRec dropDestroyCB[] = {
  1285.         {DropDestroyCB, NULL},
  1286.         {NULL, NULL}
  1287.     };
  1288.  
  1289.     XmDropProcCallbackStruct    *cb = (XmDropProcCallbackStruct *)call;
  1290.     Display                     *display = XtDisplay(w);
  1291.     Arg                         args[10];
  1292.     int                         n;
  1293.     Boolean                     rectFound, bgFound, pixFound;
  1294.     DropTransfer                transferRec;
  1295.     XmDropTransferEntryRec      transferEntries[2];
  1296.     XmDropTransferEntryRec      *transferList = NULL;
  1297.     Cardinal                    numTransfers = 0;
  1298.     Boolean                     transferValid = False;
  1299.     RectPtr                     rect;
  1300.  
  1301.     /* Cancel the drop on invalid drop operations */
  1302.     if (!(cb->operations & XmDROP_MOVE || cb->operations & XmDROP_COPY)) {
  1303.  
  1304.         n = 0;
  1305.         cb->operation = XmDROP_NOOP;
  1306.         cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1307.         XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
  1308.         XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
  1309.     }
  1310.     else {
  1311.  
  1312.         /* Find out which nested dropsite contains the pointer */
  1313.         rect = RectFind(cb->x, cb->y);
  1314.  
  1315.         CheckTargets(cb->dragContext, display, &rectFound, &bgFound, &pixFound);
  1316.  
  1317.         /* rect !NULL indicates we are within a nested dropsite */
  1318.         if (rect) {
  1319.  
  1320.             /* MY_RECT is a possible target, we'll support it first */
  1321.             if (rectFound)
  1322.                 transferValid = True;
  1323.             else if (bgFound || pixFound) {
  1324.                 /* support only copy with the BACKGROUND and PIXMAP targets */
  1325.                 if (cb->operation != XmDROP_COPY)
  1326.                     cb->operation = XmDROP_COPY;
  1327.                 transferValid = True;
  1328.             }
  1329.  
  1330.         }
  1331.         else {
  1332.             if (rectFound)
  1333.                 transferValid = True;
  1334.         }
  1335.  
  1336.         if (transferValid) {
  1337.  
  1338.             /* intialize data to send to drop transfer callback */
  1339.             transferRec = (DropTransfer) XtMalloc(sizeof(DropTransferRec));
  1340.             transferRec->widget = w;
  1341.             transferRec->x = cb->x;
  1342.             transferRec->y = cb->y;
  1343.  
  1344.             /* order of support is MY_RECT, then BACKGROUND, then PIXMAP */
  1345.             if (rectFound)
  1346.                 transferEntries[0].target = XmInternAtom(display, 
  1347.                                                          "_MY_RECTANGLE", 
  1348.                                                          False);
  1349.             else if (bgFound)
  1350.                 transferEntries[0].target = XmInternAtom(display, 
  1351.                                                          "BACKGROUND", 
  1352.                                                          False);
  1353.             else if (pixFound)
  1354.                 transferEntries[0].target = XmInternAtom(display, 
  1355.                                                          "PIXMAP",
  1356.                                                          False);
  1357.  
  1358.             transferEntries[0].client_data = (XtPointer) transferRec;
  1359.  
  1360.             /* Set up move targets */
  1361.             if (cb->operation == XmDROP_MOVE) {
  1362.  
  1363.                 transferEntries[1].client_data = (XtPointer) transferRec;
  1364.                 transferEntries[1].target = XmInternAtom(display, 
  1365.                                                          "DELETE", False);
  1366.                 numTransfers = 2;
  1367.  
  1368.             }
  1369.             else if (cb->operation == XmDROP_COPY)
  1370.                 numTransfers = 1;
  1371.  
  1372.             transferList = transferEntries;
  1373.  
  1374.             /* Setup transfer list */
  1375.             n = 0;
  1376.             cb->dropSiteStatus = XmVALID_DROP_SITE;
  1377.             XtSetArg(args[n], XmNdropTransfers, transferList); n++;
  1378.             XtSetArg(args[n], XmNnumDropTransfers, numTransfers); n++;
  1379.  
  1380.             /* Setup destroy callback to free transferRec */
  1381.             dropDestroyCB[0].closure = (XtPointer) transferRec;
  1382.             XtSetArg(args[n], XmNdestroyCallback, dropDestroyCB); n++;
  1383.  
  1384.             /* Setup transfer proc to accept the drop transfer data */
  1385.             XtSetArg(args[n], XmNtransferProc, TransferProcCallback); n++;
  1386.  
  1387.         }
  1388.         else {
  1389.  
  1390.             n = 0;
  1391.             cb->operation = XmDROP_NOOP;
  1392.             cb->dropSiteStatus = XmINVALID_DROP_SITE;
  1393.             XtSetArg(args[n], XmNtransferStatus, XmTRANSFER_FAILURE); n++;
  1394.             XtSetArg(args[n], XmNnumDropTransfers, 0); n++;
  1395.  
  1396.         }
  1397.  
  1398.     }
  1399.  
  1400.     XmDropTransferStart(cb->dragContext, args, n);
  1401.  
  1402. }
  1403.  
  1404.  
  1405. /* This procedure is used with the drop help dialog to continue with the drop */
  1406. /* ARGSUSED */
  1407. static void
  1408. #ifdef _NO_PROTO
  1409. HandleOK(w, client, call)
  1410. Widget w;
  1411. XtPointer client;
  1412. XtPointer call;
  1413. #else
  1414. HandleOK(Widget w, XtPointer client, XtPointer call)
  1415. #endif /* _NO_PROTO */
  1416. {
  1417.  
  1418.     XmDropProcCallbackStruct    *cb = (XmDropProcCallbackStruct *)client;
  1419.  
  1420.     cb->operation = appInfo->operation;
  1421.     HandleDrop(w, (XtPointer) cb);
  1422.  
  1423. }
  1424.  
  1425.  
  1426. /* This procedure is used with the drop help dialog to cancel the drop */
  1427. /* ARGSUSED */
  1428. static void
  1429. #ifdef _NO_PROTO
  1430. CancelDrop(w, client, call)
  1431. Widget w;
  1432. XtPointer client;
  1433. XtPointer call;
  1434. #else
  1435. CancelDrop(Widget w, XtPointer client, XtPointer call)
  1436. #endif /* _NO_PROTO */
  1437. {
  1438.  
  1439.     XmDropProcCallbackStruct    *cb = (XmDropProcCallbackStruct *)client;
  1440.     Arg                         args[2];
  1441.  
  1442.     /* On help, we need to cancel the drop transfer */
  1443.     XtSetArg(args[0], XmNtransferStatus, XmTRANSFER_FAILURE);
  1444.     XtSetArg(args[1], XmNnumDropTransfers, 0);
  1445.  
  1446.     /* we need to start the drop transfer to cancel the transfer */
  1447.     XmDropTransferStart(cb->dragContext, args, 2);
  1448.  
  1449. }
  1450.  
  1451.  
  1452. #ifdef _NO_PROTO
  1453. XtCallbackProc ChangeOperation(widget, client_data, call_data)
  1454. Widget widget;
  1455. XtPointer client_data;
  1456. XmAnyCallbackStruct *call_data;
  1457. #else
  1458. XtCallbackProc ChangeOperation(Widget widget, XtPointer client_data,
  1459. XmAnyCallbackStruct *call_data)
  1460. #endif
  1461. {
  1462.  
  1463.     if (client_data == 0)
  1464.         appInfo->operation = XmDROP_MOVE;
  1465.     else
  1466.         appInfo->operation = XmDROP_COPY;
  1467.  
  1468. }
  1469.  
  1470.  
  1471. /* This procedure manages the help dialog and determines which
  1472.  * message is displayed in the dialog depending on the position
  1473.  * and the type of drop.
  1474.  */
  1475. /* ARGSUSED */
  1476. static void
  1477. #ifdef _NO_PROTO
  1478. HandleHelp(w, call)
  1479. Widget w;
  1480. XtPointer call;
  1481. #else
  1482. HandleHelp(Widget w, XtPointer call)
  1483. #endif /* _NO_PROTO */
  1484. {
  1485.  
  1486.     XmDropProcCallbackStruct        *cb = (XmDropProcCallbackStruct *)call;
  1487.     static XmDropProcCallbackStruct client;
  1488.     Boolean                         rectFound, bgFound, pixFound;
  1489.     XmString                        helpStr;
  1490.     RectPtr                         rect;
  1491.     Arg                             args[5];
  1492.     XmString                        tempStr, buttonArray[2];
  1493.     int                             n = 0;
  1494.  
  1495.     /* the drop is valid until it is determined invalid */
  1496.     cb->dropSiteStatus = XmVALID_DROP_SITE;
  1497.  
  1498.     /* if we haven't created a help dialog, create one now */
  1499.     if (helpDialog == NULL) {
  1500.  
  1501.         XtSetArg(args[n], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); n++;
  1502.         XtSetArg(args[n], XmNtitle, "Drop Help"); n++;
  1503.         helpDialog = XmCreateMessageDialog(topLevel, "Help", args, n);
  1504.  
  1505.         n = 0;
  1506.         buttonArray[0] = XmStringCreateSimple("Move");
  1507.         buttonArray[1] = XmStringCreateSimple("Copy");
  1508.         XtSetArg(args[n], XmNbuttons, buttonArray); n++;
  1509.         XtSetArg(args[n], XmNbuttonCount, 2); n++;
  1510.         XtSetArg(args[n], XmNbuttonSet, 0); n++;
  1511.         XtSetArg(args[n], XmNsimpleCallback, ChangeOperation); n++;
  1512.         tempStr = XmStringCreateSimple("Operations:");
  1513.         XtSetArg(args[n], XmNoptionLabel, tempStr); n++;
  1514.         helpMenu = XmCreateSimpleOptionMenu(helpDialog, "helpMenu", args, n);
  1515.         XmStringFree(tempStr);
  1516.         XmStringFree(buttonArray[0]);
  1517.         XmStringFree(buttonArray[1]);
  1518.  
  1519.         XtAddCallback(helpDialog, XmNokCallback,
  1520.                       (XtCallbackProc) HandleOK, (XtPointer) &client);
  1521.         XtAddCallback(helpDialog, XmNcancelCallback,
  1522.                       (XtCallbackProc) CancelDrop, (XtPointer) &client);
  1523.  
  1524.         XtUnmanageChild(XmMessageBoxGetChild(helpDialog, XmDIALOG_HELP_BUTTON));
  1525.  
  1526.         XtRealizeWidget(helpDialog);
  1527.  
  1528.     }
  1529.  
  1530.     /* pass the necessary callback information along */
  1531.     client.dragContext = cb->dragContext;
  1532.     client.x = cb->x;
  1533.     client.y = cb->y;
  1534.     client.dropSiteStatus = cb->dropSiteStatus;
  1535.     client.operation = cb->operation;
  1536.     client.operations = cb->operations;
  1537.  
  1538.     /* find the valid targets */
  1539.     CheckTargets(cb->dragContext, XtDisplay(w), &rectFound, 
  1540.                  &bgFound, &pixFound);
  1541.  
  1542.     /* determine the appropriate help message */
  1543.     if (rectFound) {
  1544.  
  1545.         if (cb->operations == XmDROP_MOVE | XmDROP_COPY) {
  1546.             XtManageChild(helpMenu);
  1547.             helpStr = XmStringCreateLtoR(HELP_MSG4, XmFONTLIST_DEFAULT_TAG);
  1548.             XtManageChild(XmMessageBoxGetChild(helpDialog, XmDIALOG_OK_BUTTON));
  1549.         }
  1550.         else if (cb->operation == XmDROP_MOVE) {
  1551.             XtUnmanageChild(helpMenu);
  1552.             helpStr = XmStringCreateLtoR(HELP_MSG2, XmFONTLIST_DEFAULT_TAG);
  1553.             XtManageChild(XmMessageBoxGetChild(helpDialog, XmDIALOG_OK_BUTTON));
  1554.         }
  1555.         else if (cb->operation == XmDROP_COPY) {
  1556.             XtUnmanageChild(helpMenu);
  1557.             helpStr = XmStringCreateLtoR(HELP_MSG3, XmFONTLIST_DEFAULT_TAG);
  1558.             XtManageChild(XmMessageBoxGetChild(helpDialog, XmDIALOG_OK_BUTTON));
  1559.         }
  1560.  
  1561.     }
  1562.     else if (bgFound || pixFound && cb->operation == XmDROP_COPY) {
  1563.  
  1564.         XtUnmanageChild(helpMenu);
  1565.         rect = RectFind(cb->x, cb->y);
  1566.         if (rect) {
  1567.             helpStr = XmStringCreateLtoR(HELP_MSG1, XmFONTLIST_DEFAULT_TAG);
  1568.             XtManageChild(XmMessageBoxGetChild(helpDialog, XmDIALOG_OK_BUTTON));
  1569.         }
  1570.         else {
  1571.             helpStr = XmStringCreateLtoR(HELP_MSG5, XmFONTLIST_DEFAULT_TAG);
  1572.             XtUnmanageChild(XmMessageBoxGetChild(helpDialog, 
  1573.                             XmDIALOG_OK_BUTTON));
  1574.         }
  1575.  
  1576.     }
  1577.     else {
  1578.         XtUnmanageChild(helpMenu);
  1579.         helpStr = XmStringCreateLtoR(HELP_MSG5, XmFONTLIST_DEFAULT_TAG);
  1580.         XtUnmanageChild(XmMessageBoxGetChild(helpDialog, XmDIALOG_OK_BUTTON));
  1581.     }
  1582.  
  1583.     /* set the help message into the dialog */
  1584.     XtSetArg(args[0], XmNmessageString, helpStr);
  1585.     XtSetValues(helpDialog, args, 1);
  1586.  
  1587.     /* Free the XmString */
  1588.     XmStringFree(helpStr);
  1589.  
  1590.     /* map the help dialog */
  1591.     XtManageChild(helpDialog);
  1592.  
  1593. }
  1594.  
  1595.  
  1596. /* The procedure either begins the drop of initiates the help dialog
  1597.  * depending on the dropAction.
  1598.  */
  1599. /* ARGSUSED */
  1600. static void
  1601. #ifdef _NO_PROTO
  1602. DropProcCallback(w, client, call)
  1603. Widget w;
  1604. XtPointer client;
  1605. XtPointer call;
  1606. #else
  1607. DropProcCallback(Widget w, XtPointer client, XtPointer call)
  1608. #endif /* _NO_PROTO */
  1609. {
  1610.  
  1611.     XmDropProcCallbackStruct    *cb = (XmDropProcCallbackStruct *)call;
  1612.  
  1613.     if (appInfo->highlightRect != NULL)
  1614.         RectUnhighlight(w);
  1615.  
  1616.     if (cb->dropAction != XmDROP_HELP)
  1617.         HandleDrop(w, call);
  1618.     else
  1619.         HandleHelp(w, call);
  1620.  
  1621. }
  1622.  
  1623.  
  1624. /* This procedure registers the drop taragets and the drop site */
  1625. static void
  1626. #ifdef _NO_PROTO
  1627. RegisterDropSite(w)
  1628. Widget w;
  1629. #else
  1630. RegisterDropSite(Widget w)
  1631. #endif /* _NO_PROTO */
  1632. {
  1633.  
  1634.     Display *display = XtDisplay(w);
  1635.     Atom    targets[3];
  1636.     Arg     args[5];
  1637.     int     n = 0;
  1638.  
  1639.     /* Only accept moves or copies */
  1640.     XtSetArg(args[n], XmNdragOperations, XmDROP_COPY | XmDROP_MOVE); n++;
  1641.  
  1642.     /* set all possible targets for any of the nested drop sites */
  1643.     targets[0] = XmInternAtom(display, "_MY_RECTANGLE", False);
  1644.     targets[1] = XmInternAtom(display, "BACKGROUND", False);
  1645.     targets[2] = XmInternAtom(display, "PIXMAP", False);
  1646.     XtSetArg(args[n], XmNimportTargets, targets); n++;
  1647.     XtSetArg(args[n], XmNnumImportTargets, 3); n++;
  1648.  
  1649.     /* register a dragProc - necessary for simulating nested drop sites */
  1650.     XtSetArg(args[n], XmNdragProc, DragProcCallback); n++;
  1651.  
  1652.     /* register a dropProc */
  1653.     XtSetArg(args[n], XmNdropProc, DropProcCallback); n++;
  1654.     XmDropSiteRegister(w, args, n);
  1655.  
  1656. }
  1657.  
  1658.  
  1659. static void
  1660. #ifdef _NO_PROTO
  1661. SetInvalidIcon(w)
  1662. Widget w;
  1663. #else
  1664. SetInvalidIcon(Widget w)
  1665. #endif /* _NO_PROTO */
  1666. {
  1667.  
  1668.     Widget      invalidIcon;
  1669.     char        *invalid_bits;
  1670.     Dimension   width, height;
  1671.     Arg         args[1];
  1672.  
  1673.     if (appInfo->maxCursorWidth >= ICON_WIDTH &&
  1674.         appInfo->maxCursorHeight >= ICON_HEIGHT) {
  1675.         invalid_bits = (char *)INVALID_ICON_BITS;
  1676.         width = ICON_WIDTH;
  1677.         height = ICON_HEIGHT;
  1678.     } else {
  1679.         /* If the server will handle a small icon, create one */
  1680.         invalid_bits = (char *)SMALL_INVALID_ICON_BITS;
  1681.         width = SMALL_ICON_WIDTH;
  1682.         height = SMALL_ICON_HEIGHT;
  1683.     }
  1684.  
  1685.     invalidIcon = GetDragIconFromBits(w, invalid_bits, invalid_bits, width, 
  1686.                                       height, GetColor(DRAW_AREA_FG_COLOR),
  1687.                                       GetColor(DRAW_AREA_BG_COLOR));
  1688.  
  1689.     XtSetArg(args[0], XmNdefaultInvalidCursorIcon, invalidIcon);
  1690.     XtSetValues(XmGetXmScreen(XtScreen(w)), args, 1);
  1691.  
  1692. }
  1693.  
  1694.  
  1695. /* This procedure initalizes the toolkit and other application information */
  1696. static void
  1697. #ifdef _NO_PROTO
  1698. InitializeApplication(argc, argv)
  1699. int *argc;
  1700. String *argv;
  1701. #else
  1702. InitializeApplication(int *argc, String *argv)
  1703. #endif /* _NO_PROTO */
  1704. {
  1705.  
  1706.     static XtActionsRec new_actions[] = {
  1707.         {"StartRect", StartRect},
  1708.         {"ExtendRect", ExtendRect},
  1709.         {"EndRect", EndRect},
  1710.         {"StartMove", StartMove},
  1711.         {"ColorRect", ColorRect},
  1712.     };
  1713.     Arg         args[5];
  1714.     Cardinal    n = 0;
  1715.  
  1716.     /* Ininialize struct that hold global information */
  1717.     InitializeAppInfo();
  1718.  
  1719.     /* Initialize Toolkit and create shell */
  1720.     XtSetArg(args[n], XmNwidth, 295); n++;
  1721.     XtSetArg(args[n], XmNheight, 270); n++;
  1722.     topLevel = XtAppInitialize(&appContext, "DNDDemo", NULL, 0, 
  1723.                                argc, argv, NULL, args, n);
  1724.  
  1725.     /* Set drag protocol styles */
  1726.     n = 0;
  1727.     XtSetArg(args[n], XmNdragInitiatorProtocolStyle, 
  1728.              XmDRAG_PREFER_RECEIVER); n++;
  1729.     XtSetArg(args[n], XmNdragReceiverProtocolStyle, XmDRAG_DYNAMIC); n++;
  1730.     XtSetValues(XmGetXmDisplay(XtDisplay(topLevel)), args, n);
  1731.  
  1732.     /* Initialize tables for holding rectangle information */
  1733.     InitializeRectDpyTable();
  1734.  
  1735.     /* Add new actions for use with translation tables */
  1736.     XtAppAddActions(appContext, new_actions, 5);
  1737.  
  1738.     /* Get the display server's best cursor size */
  1739.     XQueryBestCursor(XtDisplay(topLevel), 
  1740.                      RootWindowOfScreen(XtScreen(topLevel)), 64, 64, 
  1741.                      &appInfo->maxCursorWidth, &appInfo->maxCursorHeight);
  1742.  
  1743. }
  1744.  
  1745.  
  1746. /* This the program start procedure */
  1747. void
  1748. #ifdef _NO_PROTO
  1749. main (argc, argv)
  1750. int argc;
  1751. String *argv;
  1752. #else
  1753. main (int argc, String *argv)
  1754. #endif /* _NO_PROTO */
  1755. {
  1756.  
  1757.     /* Initialize toolkit and application global values */
  1758.     InitializeApplication(&argc, argv);
  1759.  
  1760.     /* Create main window, drawing area, and color labels */
  1761.     CreateLayout();
  1762.  
  1763.     /* Register the drawing area as a drop site */
  1764.     RegisterDropSite(drawingArea);
  1765.  
  1766.     SetInvalidIcon(drawingArea);
  1767.  
  1768.     /* Realize and map widget hiearchy */
  1769.     XtRealizeWidget(topLevel);
  1770.  
  1771.     /* Create GC for drawing rectangles */
  1772.     CreateRectGC();
  1773.  
  1774.     /* Begin event loop processing */
  1775.     XtAppMainLoop(appContext);
  1776.  
  1777. }
  1778.